/*
 * MonomialIdealDecompose.java
 *
 * Created on February 22, 2005, 1:51 PM
 */

package com.milowski.monos.component;


import com.milowski.monos.*;
import com.milowski.monos.monomial.*;
import com.milowski.monos.tools.Shell;
import java.util.Iterator;
import org.infoset.component.Component;
import org.infoset.component.ItemFilterComponent;
import org.infoset.xml.Document;
import org.infoset.xml.Element;
import org.infoset.xml.InfosetFactory;
import org.infoset.xml.ItemConstructor;
import org.infoset.xml.ItemDestination;
import org.infoset.xml.Name;
import org.infoset.xml.XMLException;
import org.infoset.xml.filter.SubtreeFilter;

/**
 *
 * @author R. Alexander Milowski
 */
public class MonomialIdealDecompose extends MonosComponentBase
{
   
   static final Name componentName = InfosetFactory.createName(XML.STEPS_NAMESPACE,"decompose");
   static Name [] subtreeNames = { XML.decomposeName };
   static {
      try {
         Shell.init();
      } catch (Exception ex) {
         ex.printStackTrace();
      }
   }

   public static class ComponentFilter extends SubtreeFilter {
      
      int generatorMaximum;
      int variableMaximum;
      ComponentFilter() {
         super(subtreeNames);
      }
      public void process(Document doc) 
         throws XMLException
      {
         Element top = doc.getDocumentElement();
         String algValue = top.getAttributeValue("algorithm");
         boolean alexdual = algValue==null || algValue.equals("alexdual");
         String outputValue = top.getAttributeValue("output");
         boolean mathmlOutput = outputValue!=null && outputValue.equals("mathml");
         boolean monosOutput = outputValue!=null && outputValue.equals("monos");

         Iterator<Element> mideals = top.getElementsByName(XML.monomialIdealName);
         Element representation = mideals.hasNext() ? mideals.next() : null;
         if (representation==null) {
            XML.error(output,"Cannot find path /[m:]decompose/[m:]monomial-ideal in input.");
            return;
         }
         Object obj = XML.unmarshall(representation);
         if (!(obj instanceof MonomialIdeal)) {
            XML.error(output,"The result of unmarshalling was not a MonomialIdeal isntance.  Found "+obj.getClass().getName());
            return;
         }
         MonomialIdeal unminimized = (MonomialIdeal)obj;
         try {
            if (unminimized.getLexOrder().size()>variableMaximum) {
               XML.error(output,"The number of variables is too large: "+unminimized.getLexOrder().size()+" > "+variableMaximum);
               return;
            }
            MonomialIdeal ideal = minimize(unminimized);
            LexOrderedList components = alexdual ? 
               IdealGenerator.decompose(true,ideal) : 
               IdealGenerator.scarfMethodDecompose(ideal);
            output(mathmlOutput,monosOutput,components);
         } catch (Exception ex) {
            throw new XMLException("Parse exception: "+ex.getMessage());
         }
      }
      
      protected MonomialIdeal minimize(LexOrderedList l) {
         MonomialTree mtree = new MonomialTree(l.getLexOrder());
         mtree.add(l);
         mtree.minimize();
         return mtree.getIdealGenerator();
      }

      protected void output(boolean asMathML,boolean asMonos,LexOrderedList components) 
         throws XMLException
      {
         ItemConstructor constructor = InfosetFactory.getDefaultInfoset().createItemConstructor();
         if (asMathML) {
            post(constructor.createElement(MathML.MathML_mathName));
            MathML.outputIntersection(constructor,output,components);
            post(constructor.createElementEnd(MathML.MathML_mathName));
         } else if (asMonos) {
            post(constructor.createElement(XML.expressionName));
            post(constructor.createCharacters(components.toString()));
            post(constructor.createElementEnd(XML.expressionName));
         } else {
            components.toXML(constructor, output);
         }
      }

   }
   
   /** Creates a new instance of KernelBasisComponent */
   public MonomialIdealDecompose()
   {
      super(componentName);
   }
   
   public Component newInstance() 
      throws XMLException
   {
      final ComponentFilter filter = new ComponentFilter();
      return new ItemFilterComponent(name,vendor,version,filter,inputPortName,outputPortName) 
      {
         public void init(Component.Context context) 
            throws XMLException
         {
            Object o = context.getParameter(InfosetFactory.createName("variable-max"));
            filter.variableMaximum = o==null ? 0 : Integer.parseInt(o.toString());
            o = context.getParameter(InfosetFactory.createName("generator-max"));
            filter.generatorMaximum= o==null ? 0 : Integer.parseInt(o.toString());
         }
      };
   }
   
}
